06. setTimeout
Running Code Later
Similarly to .addEventListener() code being run at some later point, there is the setTimeout() function that will run code at a point later in time. The setTimeout() function takes:
- a function to run at some later time
- the number of milliseconds the code should wait before running the function
Let's check out an example:
setTimeout(function sayHi() {
console.log('Howdy');
}, 1000);
If we ran this code, the string 'Howdy' would appear in the console in about 1,000 milliseconds or in just about 1 second.
Since setTimeout() is an API provided by the browser, the call to setTimeout() gives the sayHi() function over to the browser which it starts a timer. After the timer is finished, the sayHi() function moves to the Queue. If the Call Stack is empty, then the sayHi() function is moved to the Call Stack and executed.
setTimeout() with Delay of 0
An interesting aspect to setTimeout() is that we can pass it a delay of 0 milliseconds.
setTimeout(function sayHi() {
console.log('Howdy');
}, 0); // ← 0 milliseconds!
You might think that since it has a delay of 0 milliseconds, that the sayHi function would run immediately. However, it still goes through the JavaScript Event Loop. So the function is handed off to the browser where the browser starts a timer for 0 milliseconds. Since the timer ends immediately, the sayHi function will move to the Queue, and then to the Call Stack once the Call Stack has finished executing any currently-running tasks.
So why is this helpful? Well, this technique can help us to convert potentially long-running code to one that's broken up to allow for the browser to handle user interactions!
Break Up Long-Running Code
Do you remember back to a previous section when we wrote JavaScript code to add two hundred paragraphs to the page? Now, instead of adding two hundred paragraphs to the page, what if we added twenty thousand? That's a lot of elements to create, append, and insert into the page!
Now keep in mind how reflow and repaint affect an app's performance. We want to write our JavaScript code to take into consideration reflow and repaint and to cause the fewest number of these.
However, we also want to make sure our app is responsive to user interaction. While JavaScript is running, the page is "busy" and the user won't be able to interact with the page (e.g. clicking a button, filling out a form). Remember that this is because JavaScript runs synchronously. So it will run to completion (creating, appending, and inserting all twenty thousand elements), and it does this before it is able to respond to any actions the user has taken. The function creates all of these elements and adds the to the page will be in the Call Stack until it's completely finished.
One way to give the user a chance to interact with the page is to break up the adding of the content into chunks. Let's do this with setTimeout():
let count = 1
function generateParagraphs() {
const fragment = document.createDocumentFragment();
for (let i = 1; i <= 500; i++) {
const newElement = document.createElement('p');
newElement.textContent = 'This is paragraph number ' + count;
count = count + 1;
fragment.appendChild(newElement);
}
document.body.appendChild(fragment);
if (count < 20000) {
setTimeout(generateParagraphs, 0);
}
}
generateParagraphs();
This code starts off by setting a count variable to 1. This will keep track of the number of paragraphs that have been added. The generateParagraphs() function will add 500 paragraphs to the page each time it's invoked. The interesting thing is that there's a setTimeout() call at the end of the generateParagraphs() function. If there less than twenty thousand elements, then it setTimeout() will be used to call the generateParagraphs() function.
If you try running this code on a page, you can still interact with the page while the code is running. It doesn't lock up or freeze the page. And it doesn't lock up or freeze because of the setTimeout() calls.
setTimeout() Recap
The browser-provided setTimeout() function takes another function and a delay, and invokes the function after the delay has passed.
Knowing how the JavaScript Event Loop works, we can use the setTimeout() method to help us write code that allows the browser to handle user interactions.